<template>
<div class="machine-dir-tree full-height">
  <div class="dir-tree-head row no-wrap bg-primary text-white">
    <q-icon name="iconfont icontubiao-103 margin-r-10 margin-t-10"></q-icon>
    <span class="head-name">机床</span>
    <q-space></q-space>
    <select-input ref="selectInput" style="width: 180px"
                  :list="searchCondition" @search="inputSearch" @clearSearchVal="clearSearchVal" />
    <q-icon :name="sendStatus==='many'?'iconfont icontubiao-143':'iconfont icontubiao-142'" class="icon">
      <q-tooltip>发送</q-tooltip>
      <q-menu anchor="bottom right" self="top right">
        <q-list dense style="min-width: 90px">
          <q-item clickable v-close-popup :active="sendStatus==='single'" active-class="sel-active">
            <q-item-section @click="changeSendNum('single')">
              发送单台
            </q-item-section>
          </q-item>
          <q-item clickable v-close-popup :active="sendStatus==='many'" active-class="sel-active">
            <q-item-section @click="changeSendNum('many')">
              发送多台
            </q-item-section>
          </q-item>
        </q-list>
      </q-menu>
    </q-icon>
    <q-icon name="iconfont icontubiao-62" class="icon">
      <q-tooltip anchor="bottom left" self="center left">排序</q-tooltip>
      <q-menu anchor="bottom right" self="top right">
        <q-list dense style="min-width: 150px">
          <q-item clickable :active="sort.name==='name'" active-class="sel-active">
            <q-item-section>
              <q-radio @input="initTree(folder)" v-model="sort.name" val="name" label="设备名称"/>
            </q-item-section>
          </q-item>
          <q-item clickable :active="sort.name==='type'" active-class="sel-active">
            <q-item-section>
              <q-radio @input="initTree(folder)" v-model="sort.name" val="type" label="数控类型"/>
            </q-item-section>
          </q-item>
          <q-separator />
          <q-item clickable :active="sort.val==='asc'" active-class="sel-active">
            <q-item-section>
              <q-radio @input="initTree(folder)" v-model="sort.val" val="asc" label="升序"/>
            </q-item-section>
          </q-item>
          <q-item clickable :active="sort.val==='desc'" active-class="sel-active">
            <q-item-section>
              <q-radio @input="initTree(folder)" v-model="sort.val" val="desc" label="降序"/>
            </q-item-section>
          </q-item>
        </q-list>
      </q-menu>
    </q-icon>
  </div>
  <q-scroll-area :thumb-style="CommonConfig.thumbStyle" class="q-pa-sm q-gutter-sm dir-tree">
    <q-tree :nodes="folder" node-key="hash" ref="machineFolderTree" :selected.sync="selected"
            no-nodes-label="暂无数据"
            :tick-strategy="sendStatus==='many'?'strict':'none'" :ticked.sync="ticked" @update:ticked="tickFun"
            @lazy-load="getFolderChildList" @update:selected="selectTree"
            selected-color="primary"/>
  </q-scroll-area>
</div>
</template>

<script>
import SelectInput from 'src/components/select-input'
import { getMachineTree, getStoreInfo, getFileInfo } from 'src/boot/program/machine'
import { defaultSchemesClearer, getFiletype } from 'src/assets/js/util'
import { mapGetters } from 'vuex'
export default {
  name: 'machine-dir-tree',
  props: {
    // 发送多台many 发送单台 single
    sendStatus: {
      type: String,
      default: 'single'
    },
    client: {},
    // mqtt唯一标识
    requestId: {
      type: String
    }
  },
  data () {
    return {
      // 搜索条件
      searchCondition: [{ id: 'name', name: '设备名称' }, { id: 'type', name: '数控类型' }],
      searchBy: '',
      searchName: '',
      sort: {
        name: 'name', // name type
        val: 'asc' // asc desc
      },
      selected: null, // 树形选中数据
      selectedCopy: null, // 树形选中数据
      ticked: [], // 勾选的hash数据
      folder: [], // 设备文件夹列表
      folderCopy: [] // 设备文件夹列表备份
      // requestId: '', // 唯一的userId用于连接盒子，此id必须唯一
      //  mqtt实例
      // client: null,
      // boxId: '' // 当前订阅的boxId
    }
  },
  computed: {
    ...mapGetters([
      'userInfo'
    ])
  },
  created () {
    this.getInfo()
  },
  methods: {
    initInfo () {
      this.clearSearchVal()
      this.$emit('setSendStatus', 'single')
      this.$emit('getFile', [])
      this.selected = null
      this.selectedCopy = null
      this.ticked = []
      this.folder = []
      this.folderCopy = []
      this.getInfo()
    },
    // 获取组织设备数据
    getInfo () {
      // 生成一个唯一的userId用于连接盒子，此id必须唯一
      // this.requestId = 'webClient' + this.userInfo.user_id.toString() + Date.parse(new Date()).toString()
      // let folder = []
      getMachineTree().then(res => {
        let folder = defaultSchemesClearer.clear(res.data)
        this.folder = this.initTree(folder)
        this.folderCopy = JSON.parse(JSON.stringify(this.folder))
        this.clearTick()
      })
    },
    initTree (tree) {
      let newTree = tree.map(item => {
        if (item.childrenCount > 0) {
          item.children = this.initTree(item.children)
          item.children = item.children.sort((a, b) => {
            if (a.level === 5 && b.level === 5 && this.sort.val === 'asc') {
              if (this.sort.name === 'name') {
                return this.sortFun(a.deviceName, b.deviceName)
                // return a.deviceName - b.deviceName
              } else {
                return this.sortFun(a.nctype, b.nctype)
                // return a.nctype - b.nctype
              }
            } else if (a.level === 5 && b.level === 5 && this.sort.val === 'desc') {
              if (this.sort.name === 'name') {
                return this.sortFun(b.deviceName, a.deviceName)
                // return a.deviceName - b.deviceName
              } else {
                return this.sortFun(b.nctype, a.nctype)
                // return a.nctype - b.nctype
              }
            }
            return a.level - b.level
          })
        }
        if (item.level === 5) {
          item.label = this.sort.name === 'name' ? item.deviceName : `${item.deviceName}(${item.nctype.length > 0 ? item.nctype : '--'})`
        }
        let icon = item.level === 5 ? 'iconfont icontubiao-60' : ''
        let iconColor = item.level === 5 ? 'secondary' : ''
        let disabled = item.level === 5 && !item.bindBox
        return {
          ...item,
          hash: item.hash ? item.hash : item.id,
          selectable: false,
          icon,
          iconColor,
          lazy: item.bindBox,
          disabled,
          noTick: true
        }
      })
      return newTree
    },
    // 排序函数
    sortFun (a, b) {
      let n = !isNaN(a - 0), n2 = !isNaN(b - 0)
      // 数字优先
      if (n && n2) {
        return a - b
      } else if (n) {
        return -1
      } else if (n2) {
        return 1
      }

      // 将含有汉字的使用localeCompare排序
      let e = escape(a).indexOf('%u') > -1, e2 = escape(b).indexOf('%u') > -1
      if (e && e2) {
        return a.localeCompare(b)
      } else if (e) {
        return 1
      } else if (e2) {
        return -1
      }
      return a.localeCompare(b)
    },
    // 搜索
    inputSearch (item, searchVal) {
      this.searchCondition.forEach(i => {
        this[i.id] = ''
      })
      this.searchBy = item.id
      this.searchName = searchVal
      this.goDir()
    },
    // 清空搜索值
    clearSearchVal () {
      this.searchCondition.forEach(i => {
        this[i.id] = ''
      })
      this.folder = JSON.parse(JSON.stringify(this.folderCopy))
      this.$refs.machineFolderTree.collapseAll()
    },
    // 跳转目录
    goDir () {
      let name = ''
      if (this.searchBy === 'name') {
        name = 'deviceName'
      } else if (this.searchBy === 'type') {
        name = 'nctype'
      }
      if (this.folder.length === 0) {
        return
      }
      this.folder = JSON.parse(JSON.stringify(this.folderCopy))
      this.folder = this.folder.filter((a, aIndex) => {
        let aFind = false
        if (a.level === 5) {
          if (a[name].indexOf(this.searchName) > -1) {
            a.label = this.searchBy === 'name' ? `${a.deviceName}` : `${a.deviceName}(${a.nctype})`
            aFind = true
          }
        } else if (a.children && a.children.length > 0) {
          a.children = a.children.filter((b, bIndex) => {
            let bFind = false
            if (b.level === 5) {
              if (b[name].indexOf(this.searchName) > -1) {
                b.label = this.searchBy === 'name' ? `${b.deviceName}` : `${b.deviceName}(${b.nctype})`
                aFind = true
                bFind = true
              }
            } else if (b.children && b.children.length > 0) {
              b.children = b.children.filter((c, cIndex) => {
                let cFind = false
                if (c.level === 5) {
                  if (c[name].indexOf(this.searchName) > -1) {
                    c.label = this.searchBy === 'name' ? `${c.deviceName}` : `${c.deviceName}(${c.nctype})`
                    aFind = true
                    bFind = true
                    cFind = true
                  }
                } else if (c.children && c.children.length > 0) {
                  c.children = c.children.filter((d, dIndex) => {
                    let dFind = false
                    if (d.level === 5) {
                      if (d[name].indexOf(this.searchName) > -1) {
                        d.label = this.searchBy === 'name' ? `${d.deviceName}` : `${d.deviceName}(${d.nctype})`
                        aFind = true
                        bFind = true
                        cFind = true
                        dFind = true
                      }
                    } else if (d.children && d.children.length > 0) {
                      d.children = d.children.filter((e, eIndex) => {
                        let eFind = false
                        if (e[name].indexOf(this.searchName) > -1) {
                          e.label = this.searchBy === 'name' ? `${e.deviceName}` : `${e.deviceName}(${e.nctype})`
                          aFind = true
                          bFind = true
                          cFind = true
                          dFind = true
                          eFind = true
                        }
                        return eFind
                      })
                    }
                    return dFind
                  })
                }
                return cFind
              })
            }
            return bFind
          })
        }
        return aFind
      })
      // findPosArr = findPosArr.sort((a, b) => {
      //   return b.length - a.length
      // })
      this.$refs.machineFolderTree.expandAll()
    },
    // 切换发送单台和多台
    changeSendNum (status) {
      this.clearTick()
      this.$emit('setSendStatus', status)
    },
    // 取消订阅
    unSubscribe (boxId) {
      this.client.unsubscribe(
        `${this.CommonConfig.mqttConfig.MQTT_TOPIC.machineFileInfo.subscribeTopic}${this.boxId}`
      )
    },
    // 获取子级列表
    getFolderChildList ({ node, key, done, fail }) {
      if (node.level === 5) {
        this.handleLevel5(node, done, fail)
      } else if (node.level > 5) {
        this.handleLevel6(node, done, fail)
        this.selected = key
      }
    },
    // 处理通过设备获取内外存储信息
    handleLevel5 (node, done, fail) {
      let params = {
        boxId: node.boxId,
        requestId: this.requestId
      }
      this.$emit('onSubscribe', node.boxId)
      // this.onSubscribe(node.boxId)
      getStoreInfo(params)
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        try {
          if (data.request_id === this.requestId && data.code === 200) {
            let inside = null, external = null, nodes = []
            // 判断是否有外部存储
            if (data.cnc) {
              inside = {
                hash: node.hash + '//',
                boxId: node.boxId,
                id: 1,
                label: `内部存储(${this.getVolume(data.cnc_use)}/${this.getVolume(data.cnc)})`,
                volumeUse: data.cnc_use,
                volume: data.cnc,
                icon: 'iconfont icontubiao-63',
                iconColor: '#333333',
                lazy: data.cnc > 0,
                source: 'machine',
                position: 'cnc',
                level: 6,
                path: '/',
                children: [],
                noTick: false
              }
              nodes.push(inside)
            }
            if (data.box) {
              external = {
                hash: node.hash + '2/',
                boxId: node.boxId,
                id: 2,
                label: `外部存储(${this.getVolume(data.box_use)}/${this.getVolume(data.box)})`,
                volumeUse: data.box_use,
                volume: data.box,
                icon: 'iconfont icontubiao-63',
                iconColor: '#333333',
                lazy: data.box > 0,
                source: 'machine',
                position: 'box',
                level: 6,
                path: '/',
                children: [],
                noTick: false
              }
              nodes.push(external)
            }
            done(nodes)
          } else {
            fail()
          }
        } catch (e) {
          console.error(e)
          this.errMessage('获取列表失败')
        }
        // this.unSubscribe(node.boxId)
      }
    },
    // 处理通过设备获取内外存储信息
    handleLevel6 (node, done, fail) {
      let params = {
        about: node.position,
        boxId: node.boxId,
        requestId: this.requestId,
        path: node.path
      }
      this.$emit('onSubscribe', node.boxId)
      // this.onSubscribe(node.boxId)
      getFileInfo(params)
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        try {
          if (data.request_id === this.requestId && data.code === 200) {
            // 判断是否有外部存储
            if (data.hasOwnProperty('box')) {
              let { dirData, fileData } = this.initMachineNodeData(node, data.box, 'box')
              let nodes = [].concat(dirData, fileData)
              this.$emit('getFile', nodes, node)
              done(dirData)
            }
            if (data.hasOwnProperty('cnc')) {
              let { dirData, fileData } = this.initMachineNodeData(node, data.cnc, 'cnc')
              let nodes = [].concat(dirData, fileData)
              this.$emit('getFile', nodes, node)
              done(dirData)
            }
          } else {
            fail()
          }
        } catch (e) {
          console.error(e)
          this.errMessage('获取列表失败')
        }
        // this.unSubscribe(node.boxId)
      }
    },
    // 初始化文件数据
    initMachineNodeData (node, info, source) {
      let dirData = [], fileData = []
      info.forEach((item, index) => {
        if (item.type === 0) {
          dirData.push({
            id: index + 1,
            hash: node.hash + (index + 1) + '/',
            boxId: node.boxId,
            label: item.name,
            size: item.size,
            isFile: false,
            icon: 'img:statics/svg/file-icon.svg',
            lazy: item.size > 0,
            edit: false,
            source: 'machine',
            position: source,
            type: 'other',
            level: node.level + 1,
            path: node.path + item.name + '/',
            timestamp: parseInt(item.modify_time * 1000),
            noTick: true,
            children: []
          })
        } else if (item.type === 1) {
          let type = getFiletype(item.name)
          fileData.push({
            id: index + 1,
            hash: node.hash + (index + 1) + '/',
            boxId: node.boxId,
            label: item.name,
            size: item.size,
            isFile: item.type === 1,
            icon: 'img:statics/svg/' + type + '.svg',
            lazy: false,
            edit: false,
            source: 'machine',
            position: source,
            type,
            level: node.level + 1,
            path: node.path + item.name,
            timestamp: parseInt(item.modify_time * 1000),
            noTick: true,
            children: []
          })
        }
      })
      return { dirData, fileData }
    },
    // 容量转换，volume单位b
    getVolume (volume) {
      let val
      if (volume / 1024 < 1) {
        val = volume
        return val + 'B'
      }
      if (volume / 1024 / 1024 < 1) {
        val = volume / 1024
        return val.toFixed(2) + 'K'
      }
      if (volume / 1024 / 1024 / 1024 < 1) {
        val = volume / 1024 / 1024
        return val.toFixed(2) + 'M'
      }
      if (volume / 1024 / 1024 / 1024 / 1024 < 1) {
        val = volume / 1024 / 1024 / 1024
        return val.toFixed(2) + 'G'
      }
      if (volume / 1024 / 1024 / 1024 / 1024 / 1024 < 1) {
        val = volume / 1024 / 1024 / 1024 / 1024
        return val.toFixed(2) + 'T'
      }
    },
    // 获取文件
    getFile (node) {
      // let { dirs, nodes } = getFolderChildList(node)
      // this.$emit('getFile', nodes, node)
      // node.children = dirs

      let params = {
        about: node.position,
        boxId: node.boxId,
        requestId: this.requestId,
        path: node.path
      }
      this.$emit('onSubscribe', node.boxId)
      // this.onSubscribe(node.boxId)
      getFileInfo(params)
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        try {
          if (data.request_id === this.requestId && data.code === 200) {
            // 判断是否是外部存储
            if (data.hasOwnProperty('box')) {
              let { dirData, fileData } = this.initMachineNodeData(node, data.box, 'box')
              let nodes = [].concat(dirData, fileData)
              this.$emit('getFile', nodes, node)
              node.children = dirData
            }
            if (data.hasOwnProperty('cnc')) {
              let { dirData, fileData } = this.initMachineNodeData(node, data.cnc, 'cnc')
              let nodes = [].concat(dirData, fileData)
              this.$emit('getFile', nodes, node)
              node.children = dirData
            }
          } else {
            node.children = []
          }
        } catch (e) {
          console.error(e)
          this.errMessage('获取文件失败')
        }
      }
    },
    // 通过右侧双击文件夹获取子文件夹内容，同时让左侧目录树位于相应的位置
    setExpand (selFiles, dirs) {
      this.selected = selFiles.hash
      this.selectedCopy = this.selected
      this.$refs.machineFolderTree.setExpanded(selFiles.hash, true)
    },
    // 目录树选择
    selectTree (target) {
      if (target === null) {
        this.selected = this.selectedCopy
      } else {
        this.selectedCopy = this.selected
      }
      let selNode = this.$refs.machineFolderTree.getNodeByKey(this.selected)
      this.getFile(selNode)
      this.$refs.machineFolderTree.setExpanded(this.selected, true)
    },
    // 目录树勾选
    tickFun () {
      let tickNodes = []
      this.ticked.forEach(item => {
        let tickNode = this.$refs.machineFolderTree.getNodeByKey(item)
        tickNodes.push(tickNode)
      })
      this.$emit('setMachineTickNodes', tickNodes)
    },
    // 清除勾选数据
    clearTick () {
      this.ticked = []
      this.$emit('setMachineTickNodes', [])
    },
    // 返回上一级目录
    backParentNode () {
      let selNode = this.$refs.machineFolderTree.getNodeByKey(this.selected)
      // let paths = selNode.path.split('/')
      // console.log(this.folder)
      // let parentPaths = paths.slice(0, paths.length - 2)
      // let parentPath = parentPaths.join('/') + '/'
      // const parentNode = this.getParentNode(parentPaths, this.folder, 0)
      let hashs = selNode.hash.split('/')
      let parentHashs = hashs.slice(0, hashs.length - 2)
      let parentHash = parentHashs.join('/') + '/'
      const parentNode = this.getParentNode(parentHash, this.folder, 0)
      this.selected = parentNode.hash
      this.selectedCopy = this.selected
      this.$refs.machineFolderTree.setExpanded(this.selected, true)
      this.getFile(parentNode)
    },
    // 获取父级node
    getParentNode (parentHash, nodes, level) {
      // let resultNode = nodes.find(item => {
      //   return (item.id && item.id === parentPaths[level])
      // })
      // console.log(resultNode)
      // if (parentPaths.length - 1 !== level) {
      //   resultNode = this.getParentNode(parentPaths, resultNode.children, level + 1)
      // }
      let resultNode = nodes.find(item => {
        return (item.hash && parentHash.indexOf(item.hash) === 0)
      })
      if (resultNode.hash !== parentHash) {
        resultNode = this.getParentNode(parentHash, resultNode.children, level + 1)
      }
      return resultNode
    }
  },
  components: {
    SelectInput
  }
}
</script>

<style scoped lang="stylus">
.dir-tree-head{
  padding 0 20px
  height 40px
  line-height 40px
  font-size 18px
  .icon {
    margin-top: 10px;
    margin-left: 10px;
    font-size: 18px;
  }
}
.sel-active{
  background-color #cfd6fe
  color #333
}
.dir-tree{
  height calc(100% - 41px)
}
</style>
